/*
 * CategoryTests.java
 *
 *  
 */
package org.msb.finance.data;

import static org.junit.Assert.*;

import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

/**
 * 
 * 
 * @author Marc Boudreau
 * 
 */
@SuppressWarnings("nls")
public class CategoryTests {

	/*
	 * 
	 */
	private Category category;

	private final String CATEGORY_NAME = "Test Category";

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		category = new Category(CATEGORY_NAME);
	}

	/**
	 * Test method for {@link org.msb.finance.data.Category#Category(java.lang.String)}.
	 */
	@Test
	public void testCategory() {
		assertNotNull(category);

		assertNotNull(new Category("Test Category"));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetFullNameWithDetached() throws Exception {
		assertEquals(CATEGORY_NAME, category.getFullName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetFullNameWithTopLevel() throws Exception {
		Cabinet cabinet = new Cabinet(null);
		cabinet.addCategory(category, null);

		assertEquals(CATEGORY_NAME, category.getFullName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetFullNameWithSubCategory() throws Exception {
		Cabinet cabinet = new Cabinet(null);
		cabinet.addCategory(category, null);

		final String NAME = "Test Subcategory";
		Category subCategory = new Category(NAME);
		cabinet.addCategory(subCategory, category);

		assertTrue(0 == subCategory.getFullName().indexOf(CATEGORY_NAME));
		assertTrue(subCategory.getFullName().endsWith(NAME));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetNameDetached() throws Exception {
		final String NAME = "Different Test Category";
		category.setName(NAME);

		assertEquals(NAME, category.getName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetNameToNullDetached() throws Exception {
		try {
			category.setName(null);
		} catch (AssertionError ex) {
			// Ignore.
		}

		assertNotNull(category.getName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetNameAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		try {
			category.setName("Different Test Category");
		} catch (AssertionError ex) {
			// Ignore.
		}

		assertEquals(CATEGORY_NAME, category.getName());
	}

	/**
	 * Test method for {@link org.msb.finance.data.Category#setName(java.lang.String)}.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetNameToNullAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		try {
			category.setName(null);
		} catch (AssertionError ex) {
			// Ignore.
		}

		assertNotNull(category.getName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testAddNullSubCategory() throws Exception {
		assertFalse(category.addSubCategory(null));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testAddSubCategory() throws Exception {
		Category subCategory = new Category("Test Subcategory");
		category.addSubCategory(subCategory);

		assertEquals(1, category.getSubCategoryCount());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testAddSubCategoryWithSameName() throws Exception {
		final String NAME = "Test Subcategory";
		Category subCategory1 = new Category(NAME);
		Category subCategory2 = new Category(NAME);

		assertTrue(category.addSubCategory(subCategory1));
		assertFalse(category.addSubCategory(subCategory2));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRemoveFromParentDetached() throws Exception {
		assertFalse(category.removeFromParent());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRemoveFromParentAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		assertTrue(category.removeFromParent());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRenameAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		assertTrue(category.rename(CATEGORY_NAME + "_ZZZ"));
		assertEquals(CATEGORY_NAME + "_ZZZ", category.getName());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRenameToSameName() throws Exception {
		assertTrue(category.rename(CATEGORY_NAME));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRenameToSameNameAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		assertTrue(category.rename(CATEGORY_NAME));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRenameToDuplicateNameAttached() throws Exception {
		Category parentCategory = new Category("Test Parent Category");
		parentCategory.addSubCategory(category);

		Category subCategory = new Category("Different Test Category");
		parentCategory.addSubCategory(subCategory);

		assertFalse(subCategory.rename(CATEGORY_NAME));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetSubCategoriesIterator() throws Exception {
		Category subCat1 = new Category("Test Subcategory 1");
		Category subCat2 = new Category("Test Subcategory 2");

		category.addSubCategory(subCat1);
		category.addSubCategory(subCat2);

		Iterator<Category> it = category.getSubCategories();
		assertEquals(subCat1, it.next());
		assertEquals(subCat2, it.next());
		assertFalse(it.hasNext());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCategoryEquals() throws Exception {
		Category b = category;
		Category c = new Category(b.getName());
		Category d = new Category(b.getName() + "-ZZZ");

		assertTrue(category.equals(b));
		assertTrue(b.equals(category));

		assertTrue(category.equals(c));
		assertTrue(c.equals(category));

		assertTrue(b.equals(c));
		assertTrue(c.equals(b));

		assertFalse(category.equals(null));

		assertFalse(category.equals(d));
		assertFalse(d.equals(category));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCategoryHashCode() throws Exception {
		Category b = new Category(category.getName());
		Category c = new Category("Random String -- 059e850285");

		assertTrue(category.hashCode() == b.hashCode());
		assertFalse(category.hashCode() == c.hashCode());

		Category d = new Category("AAAA");
		String sd = new String("AAAA");

		assertFalse(d.hashCode() == sd.hashCode());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompareTo() throws Exception {
		final Category cat1 = new Category("AAA-Test Category");
		final Category cat2 = new Category("ZZZ-Test Category");

		assertEquals(0, category.compareTo(category));

		assertTrue(0 < category.compareTo(cat1));
		assertTrue(0 > cat1.compareTo(category));

		assertTrue(0 > category.compareTo(cat2));
		assertTrue(0 < cat2.compareTo(category));
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testCompareToNull() throws Exception {
		Category c1 = new Category(null);

		try {
			category.compareTo(c1);
			fail("Expected a NullPointerException or an AssertionError to be thrown.");
		} catch (Throwable ex) {
			// Pass.
		}
	}
}
